#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pandas as pd
import sys
import json
import random
import argparse
import csv
import numpy as np
import re
from fuzzywuzzy import fuzz

from utils.text_utils import sent_tokenize,check_noise
from utils.chinese_utils import conver_word_zh
from utils.bot_json_utils import load_botjson_info


def findSlots(column):  #will return a list of all slots in 3rd party adjudication file
    slot_dictionary = {}
    slot_values = {}
    slot_names =  {}
    for index, utterance in column.items():
        if type(utterance) == str:
            #pull all the information inside the brackets
            #full_annotation = re.findall(r'\{[^\{\}]*\}',utterance) #keeps inner brackets (if nested)
            annotations_list = re.findall(r'\{([^\{\}]*)\}',utterance) #remove nested/unbalanced brackets for splitting value, name
            if annotations_list:
                slot_values[index] = [annotation.split('|')[0] for annotation in annotations_list]
                slot_names[index] = [annotation.split('|')[1]for annotation in annotations_list]
                slot_dictionary[index] = [annotation for annotation in annotations_list]
    return slot_dictionary, slot_values, slot_names


def getValuestoCheck(slot_dictionary, builtin,custom_names,custom_slots):
    # first check if slot is custom, or builtin, if it is custom, then move to custom function, if it is builtin move to builtin fuction
    FuzzyCustomSlotsDF = pd.DataFrame(columns =['Row', 'Slot', 'Issue'])
    TrueCustomSlotsDF = pd.DataFrame(columns =['Row', 'Slot', 'Issue'])
    # BuiltinSlotsDF = pd.DataFrame(columns =['Row', 'Slot', 'Issue'])
    # bot_name =     getApplicationBotName(bot_file)
    custom_check_dict = {}
    builtin_check_dict = {}

    for index, slots in slot_dictionary.items():
        custom_check_list = []
        builtin_check_list = []
        for slot in slots:
            slotName = slot.split('|')[1]
            if slotName in custom_names:
                custom_check_list.append(slot)
            elif slotName in builtin:
                builtin_check_list.append(slot)
            else:
                message = "Unknown Slot Name"
                error = [index, '{'+slot+'}', message]
                df_len = len(FuzzyCustomSlotsDF)
                FuzzyCustomSlotsDF.loc[df_len] = error
                TrueCustomSlotsDF.loc[df_len] = error
        if custom_check_list:
            custom_check_dict[index] = custom_check_list
        if builtin_check_list:
            builtin_check_dict[index] = builtin_check_list

    def fuzzy_match():  #check custom values
        for index, slotlist in custom_check_dict.items():
            for slots in slotlist:
                truecount = 0
                slotValue = slots.split('|')[0]
                slotName = slots.split('|')[1]
                slotValue = conver_word_zh(slotValue,slotName)
                all_possible_values = []
                test_values = []
                for customs in custom_slots:
                    if customs[1] == slotName: #find the name of the custom slot that matches the one in the utterance
                        all_possible_values.append(customs[0])
                for all_val in all_possible_values:
                    test_values.append(fuzz.partial_ratio(slotValue.lower(),all_val.lower())) #not case sensitive/allows some variation
                    if all_val.lower() == slotValue.lower():
                        #print(all_val.lower(), slotValue.lower())
                        truecount+=1
                fuzzycount = sum(m >= 85 for m in test_values) #count all occurrances greater than or equal to 85

                if fuzzycount <1:  #if there is not at least one match: error
                    message = 'SlotValue: {} does not belong to SlotName: {}'.format(slotValue, slotName)
                    error = [index, '{'+slots+'}' ,message]
                    df_len = len(FuzzyCustomSlotsDF)
                    FuzzyCustomSlotsDF.loc[df_len] = error
                if truecount<1:
                    message = 'SlotValue: {} does not belong to SlotName: {}'.format(slotValue, slotName)
                    error = [index, '{'+slots+'}' ,message]
                    df_len = len(TrueCustomSlotsDF)
                    TrueCustomSlotsDF.loc[df_len] = error
        return FuzzyCustomSlotsDF.sort_values('Row'), TrueCustomSlotsDF.sort_values('Row')

    FuzzyCustomSlotsDF, TrueCustomSlotsDF = fuzzy_match()
    return builtin_check_dict, FuzzyCustomSlotsDF, TrueCustomSlotsDF

# converting to df and assigning new names to the columns

def make_SentenceCounter_dataframe(conversation_dataframe):
    SentenceCounterDF = pd.DataFrame(columns =['Row','Author_Role','Utterance', 'NumberOfSentences'])

    conversation_dataframe['agent_turns'] = conversation_dataframe.loc[conversation_dataframe['author_role'] =='agent','utterance']
    indices = [index for index,utterance in conversation_dataframe['agent_turns'].items() if type(utterance) == str and '[' in utterance] #find the index of all agent utterances with a hint
    for index in indices:
        if index+1 <= len(conversation_dataframe):
            agent = conversation_dataframe.loc[index, 'agent_turns']
            customer= conversation_dataframe['user_turns'].loc[index+1] #find the sentence following the hint
            if type(customer) == str:
                number_of_sentences = sent_tokenize(customer) 
                sent_length = len(number_of_sentences)   
                if sent_length > 1:        # find all responses longer than 1
                    df_len = len(SentenceCounterDF)
                    agent_hints = [index,'agent',agent,None]
                    SentenceCounterDF.loc[df_len] = agent_hints
                    df_len = len(SentenceCounterDF)
                    customer_hints = [index+1,'customer',customer,sent_length]
                    SentenceCounterDF.loc[df_len] = customer_hints

            # SentenceCounterDF.loc[df_len] = hints
    return SentenceCounterDF


# response_after_hint = SentenceCountAfterHint(in_file, in_file['author_role'])

def dfs_tabs(df_list, sheet_list, file_name):
    '''Save output to xlxs file'''
    writer = pd.ExcelWriter(file_name,engine='xlsxwriter')
    for dataframe, sheet in zip(df_list, sheet_list):
        dataframe.to_excel(writer, sheet_name=sheet, startrow=0 , startcol=0,index=False)
    writer.save()



def make_normalization_dataframe(conversation_dataframe):
    check_items = conversation_dataframe['utterance']
    rows = check_noise(check_items)
    NormalizationDF = pd.DataFrame(rows, columns=['Row', 'Slot', 'Issue'])
    return NormalizationDF

def make_Dropped_stats_dataframe(conversation_dataframe):
    value_counts = conversation_dataframe.dropped_reason.value_counts()
    Dropped_statsDF = pd.DataFrame(value_counts)
    Dropped_statsDF = Dropped_statsDF.reset_index()
    Dropped_statsDF.columns = ['dropped reason', 'occurrences']  # change column names
    return Dropped_statsDF

def make_fuzzy_dataframe(conversation_dataframe,builtindict,custom_slots_dict):
    custom_slots = [(key, value) for key, value in custom_slots_dict.items()]
    custom_names = list(custom_slots_dict.values())
    buildinList = list(builtindict.keys())
    slot_dictionary, _, _ = findSlots(conversation_dataframe['user_turns'])

    builtincheckdict, FuzzyCustomSlotsDF, TrueCustomSlotsDF = getValuestoCheck(slot_dictionary, buildinList,
                                                                               custom_names, custom_slots)
    return FuzzyCustomSlotsDF,TrueCustomSlotsDF

def main():

    # parser = argparse.ArgumentParser()
    # parser.add_argument('--input', type=str, action="store",dest="conversations", default="",help="input the conversations file name (eg, 3rd_party_adjudication)")
    # parser.add_argument('--app', type=str, action="store",dest="application_json", default="",help="input the application.json file")
    # parser.add_argument('--output', type=str, action="store",dest="output", default="",help="input excel output file name")
    #
    # args = parser.parse_args()

    check_zh = 1
    if check_zh:
        conversations = './3rd_party_adjudication_zh_cn.csv'
        application_data = './bot_cn.json'
        output_file = './RedFlagReport_cn_JL.xlsx'
    else:
        conversations = './3rd_party_adjudication.csv'
        application_data = './bot.json'
        output_file = './RedFlagReport_JL.xlsx'


    in_file = pd.read_csv(conversations)
    in_file.index = in_file.index + 2
    in_file['user_turns'] = in_file.loc[in_file['author_role'] == 'customer', 'utterance']

    # 加载bot配置文件信息
    custom_slots_dict, builtindict = load_botjson_info(application_data)


    #生成相应的dataframe结果
    NormalizationDF = make_normalization_dataframe(in_file)
    SentenceCounterDF = make_SentenceCounter_dataframe(in_file)
    Dropped_statsDF = make_Dropped_stats_dataframe(in_file)
    FuzzyCustomSlotsDF, TrueCustomSlotsDF = make_fuzzy_dataframe(in_file,builtindict,custom_slots_dict)





    # list of dataframes and sheet names
    dfs = [NormalizationDF, SentenceCounterDF,FuzzyCustomSlotsDF,TrueCustomSlotsDF,Dropped_statsDF]
    sheets = ['Normalization','SentenceCount','FuzzyCustomSlotsCheck', 'TrueCustomSlotsCheck','DroppedStats']
    dfs_tabs(dfs, sheets, output_file)

if __name__ == '__main__':
    main()
